import java.util.HashMap;
import java.util.ArrayList;

public class PredictMap {
	static ArrayList<String> terminals;
	static ArrayList<String> nonTerminals;
	static HashMap<String,Formula> predictMap;
	/**
	 * 构建预测表需要
	 * 
	 * @param ArrayList<Formula> formula 产生式列表
	 * @param ArrayList<String> terminals 包含有所有终结符的列表
	 * @param ArrayList<String> nonTerminals 所有非终结符的列表
	 * @param HashMap<String,ArrayList<String>> firsts 作为first集合的映射
	 * @param HashMap<String, ArrayList<String>>follows 作为follows集合的映射
	 * @param HashMap<String, Formula> predictMap 产生的预测分析表，存储每个终结符和非终结符相对应的产生式
	 * 
	 */
	public static void setPredictionMap(ArrayList<Formula> formulas, ArrayList<String> terminals,
			ArrayList<String> nonTerminals, HashMap<String, ArrayList<String>> firsts,
			HashMap<String, ArrayList<String>> follows, HashMap<String, Formula> predictMap) {
		//分别组装终结符集，非终结符集，预测表
		PredictMap.terminals = terminals;
		PredictMap.nonTerminals = nonTerminals;
		PredictMap.predictMap = predictMap;
		// 1.根据First集合构建预测表
		for (Formula formula : formulas) {
			try {
				String[] right = formula.getRight();
				String left = formula.getLeft();
				//如果文法右部是空串先跳过\
				if (right[0].equals("$")) {
					continue;
				}
				//根据文法右部的第一个符号的First集合来决定如何填充预测表
				for (String terminalsInFirsts : firsts.get(right[0])) {
					//如果First集合中遇到$，进入Follow集合
					if(terminalsInFirsts.equals("$")) {
						//规则:(3) 若ε∈ FIRST(α), 则对任何b∈FOLLOW(A), 把A->ε加入M[A, b]中;
						for (String terminalInFollow : follows.get(left)) {
							predictMap.put(getMapKey(terminalInFollow, left),
									new Formula(left, new String[]{"$"}));
						}
					}
					//规则:(2) 对每个终结符a∈FIRST(α), 把A->α加入M[A, a]中;
					predictMap.put(getMapKey(terminalsInFirsts, left), formula);
				}
			} catch (Exception e) {
				//System.out.println("first集合中没有 key: " + formula.getRight()[0]);
				e.printStackTrace();
			}
		}
		//2.处理文法中遇到空串的情况
		for (Formula formula : formulas) {
			//String[] right = formula.getRight();
			String left = formula.getLeft();
			if(formula.getRight()[0].equals("$")) {
				for (String terminalInFollow : follows.get(left)) {
					predictMap.put(getMapKey(terminalInFollow, left), formula);
				}
			}
		}
	}

	// 以固定格式产生分析表的 Key
	static String getMapKey(String terminal, String nonTerminal) {
		// Terminal 为终结符，横坐标
		// nonTerminal 为非终结符，纵坐标
		return "{terminal: " + terminal + "  " + "nonterminal: " + nonTerminal + "}";
	}

	static void outPutPredictMapInConsole(){
		//输出预测表
		System.out.println("PredictMap:");
		for (String nonTerminal : nonTerminals) {
			for (String terminal : terminals) {
				String predictMapKey = PredictMap.getMapKey(terminal, nonTerminal);
				if (predictMap.get(predictMapKey) != null) {
					System.out.print("terminal:" + terminal + " " + "formula:" + nonTerminal + " -> ");
					for (String s : predictMap.get(predictMapKey).getRight()) {
						System.out.print(s);
					}
					System.out.println();
				}
			}
		}
	}
}